home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
kyocera
/
kyofonts.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-01
|
19KB
|
669 lines
/* kyofonts.c: font module for dvi printing on Kyocera laser printers
* Adapted from the qmsfonts module from Massachusetts Institute of Technology
*/
#include <stdio.h>
#include "util.h"
#include "fonts.h"
#include "findfile.h"
#include "kyo.h"
#include "preload.h"
#include <sys/stat.h>
#define MAXDVIFONTS 256 /* Max number of fonts allowed in a DVI file*/
#define MAXFNTDIR 16 /* Max number of dirs to look for fonts */
unsigned char *malloc();
char *strcat();
char *strcpy();
char *strncpy();
char *strncmp();
char *strcmp();
long numerator,denominator,half_denominator,jobmag;
long freewords = KYOMAXWORDS; /* free space on printer */
FILE *kyo; /* output device */
char *filter_name; /* the name of the calling prog */
char *fntdirvec[MAXFNTDIR];
int fntdirveclen;
int nkyofonts;
struct kyofont *curfnt; /* ptr to current and last font */
long timestamp; /* Timestamp for stamping kyo fonts */
int nloaded; /* Number of fonts already loaded */
char *loadfile = PRLOAD ;
char fontnums[MAXKYOFONTS];
#define PR_USED 0x0001
#define PR_LOADED 0x0002
struct preload {
struct preload_info *pr_font;
short pr_info;
} loaded[MAXKYOFONTS];
/* The dvifont struct provides a (possible) many-to-one mapping
* because several DVI fonts can map to the same Kyocera font during font
* substitution.
*/
struct dvifont {
unsigned long df_num; /* DVI font number */
struct kyofont *df_kyofont; /* Font which contains */
} dvifonts[MAXDVIFONTS];
int ndvifonts;
long max(a,b)
long a,b;
{
return((a>b)? a:b);
}
long min(a,b)
long a,b;
{
return((a<b)? a:b);
}
/* called at the beginning of the driver program */
f_init(printer,pgmnam,dirvec,dirveclen,num,den,mag,options)
FILE *printer;
char *pgmnam,*dirvec[];
int dirveclen;
long num,den,mag;
unsigned long options;
{
int i, n, loadf;
struct stat s;
struct preload_info *fnt;
numerator = num;
denominator = den;
half_denominator = denominator / 2;
jobmag = mag;
fntdirveclen = min(MAXFNTDIR,dirveclen);
for (i = 0; i < fntdirveclen; i++) fntdirvec[i] = dirvec[i];
ndvifonts = 0;
nkyofonts = 0;
timestamp = 0;
kyo = printer;
filter_name = pgmnam;
/* Try to read the file with information about the
* fonts loaded in the Kyocera at this moment
* The preload file should exist and have a length
* that is a multiple of the length of a preload-record
* This to protect against corrupted preload information
* When no preload information is present or when it is corrupt
* dump an explicit DAF (delete all fonts) command
*/
if (((loadf = open(loadfile, 0)) >= 0) &&
(stat(loadfile, &s) == 0) &&
(s.st_size > 0) &&
((s.st_size % sizeof(struct preload_info)) == 0)) {
n = s.st_size / sizeof(struct preload_info);
debug("%d fonts were preloaded\n", n);
for (i=0; i<n; i++) {
if (!(loaded[nloaded].pr_font = fnt =
(struct preload_info *) malloc(sizeof(struct preload_info))))
croak("malloc %d",sizeof(struct preload_info));
loaded[nloaded++].pr_info = PR_LOADED;
if (read(loadf, fnt, sizeof(struct preload_info)) !=
sizeof(struct preload_info)) {
nloaded--;
debug("Could read the info of only %d preloaded fonts\n",
nloaded);
break;
}
freewords -= fnt->pr_words_used;
fontnums[fnt->pr_kyonumber-KF_NUMBASE] = KF_USED;
debug("%s\n", fnt->pr_name);
}
close(loadf);
} else fprintf(kyo, "!R! DAF;EXIT;");
debug("Free font memory %ld words\n",freewords);
/* Clear the preload file before going on
* So when the driver crashes, it will not leave the next jobs
* with incorrect preload information
*/
close(creat(loadfile, 0644));
}
/* Called at the end of the driver program. */
f_term()
{
int i, j, loadf;
struct kyofont *fnt;
struct kyochar *c;
struct preload_info font;
struct preload *pfnt;
if ((loadf = creat(loadfile, 0644)) < 0) {
debug("Cannot create %s\n", loadfile);
return;
}
/* Just copy back the information for fonts not used by this job */
for (i=0; i<nloaded; i++) {
pfnt = &loaded[i];
if (!(pfnt->pr_info & PR_USED) &&
(pfnt->pr_info & PR_LOADED))
write(loadf, pfnt->pr_font, sizeof(struct preload_info));
}
/* Write back the information about the fonts that are used by this job */
for (i=0; i<nkyofonts; i++) {
fnt = kyofonts[i];
if (fnt->kf_info & KF_LOADED) {
font.pr_kyonumber = fnt->kf_kyonumber;
strcpy(font.pr_name, fnt->kf_name);
font.pr_mag = fnt->kf_mag;
font.pr_words_used = fnt->kf_words_used;
font.pr_tfm_checksum = fnt->kf_tfm_checksum;
for (j=0; j<4; j++) font.pr_charvec[j] = 0;
for (j=0; j<MAXCHARS; j++) {
c = &(fnt->kf_char[j]);
if (c->kc_info & KC_LOADED)
font.pr_charvec[j/32] |= (1 << (j % 32));
}
write(loadf, &font, sizeof(struct preload_info));
}
}
debug( "Font memory left: %ld words\n", freewords);
}
/* This routine provides for an independent numbering scheme
* for the fonts loaded into the Kyocera
* It returns the first free number
* Fonts are numbered starting at KF_NUMBASE
*/
short next_kyonumber()
{
int i;
for (i=0; i<MAXKYOFONTS; i++)
if (!fontnums[i]) {
fontnums[i] = KF_USED;
return(i+KF_NUMBASE);
}
}
/* Look if font "name" is preloaded
* If it is return a pointer to the preload information
* Ohterwise return 0
*/
struct preload *
preloaded(name, tfmchecksum, mag)
char *name;
long tfmchecksum;
{
int i;
struct preload *pnt;
register struct preload_info *fnt;
for (i=0; i<nloaded; i++) {
pnt = &loaded[i];
fnt = pnt->pr_font;
/* The name, magnification and tfm-checksum should match */
if ((pnt->pr_info & PR_LOADED) &&
(strcmp(fnt->pr_name, name) == 0) &&
(fnt->pr_mag == mag) &&
(fnt->pr_tfm_checksum == tfmchecksum)) {
return(pnt);
}
}
return((struct preload *) 0);
}
/* Try to locate the font "name" with the specified attributes
* in "area"
*/
struct kyofont *
find_kyofont(area,name,texmag,s,tfmchecksum)
char *area,*name;
long texmag,s,tfmchecksum;
{
char fname[MAXNAMLEN],nname[128];
int i,nmag;
int mag = (texmag * 3 + 1) / 2;
struct kyofont *fnt;
struct preload *pfnt;
struct preload_info *pnt;
/* try to find a font file */
if (!findfile(fntdirvec,fntdirveclen,area,name,mag,fname,nname,&nmag))
croak("no font %s.%d",name,texmag);
/* make a new kyocera font */
if (nkyofonts >= MAXKYOFONTS) croak("too many kyo fonts");
if (!(kyofonts[nkyofonts++] = fnt =
(struct kyofont *) malloc(sizeof(struct kyofont))))
croak("malloc %d",sizeof(struct kyofont));
fnt->kf_mag = nmag;
fnt->kf_timestamp = 0;
fnt->kf_s = s;
fnt->kf_tfm_checksum = tfmchecksum;
strcpy(fnt->kf_name,nname);
strcpy(fnt->kf_filename,fname);
for (i=0; i<MAXCHARS; i++)
fnt->kf_char[i].kc_info = 0;
if (pfnt = preloaded(nname, tfmchecksum,nmag)) {
pnt = pfnt->pr_font;
fnt->kf_kyonumber = pnt->pr_kyonumber;
fnt->kf_words_needed = 0;
fnt->kf_words_used = pnt->pr_words_used;
for (i=0; i<MAXCHARS; i++)
if (pnt->pr_charvec[i/32] & ( 1 << (i % 32)))
fnt->kf_char[i].kc_info = KC_LOADED;
fnt->kf_info = KF_FILE | KF_LOADED;
pfnt->pr_info |= PR_USED;
} else {
fnt->kf_kyonumber = next_kyonumber();
fnt->kf_words_needed = KF_MIN;
fnt->kf_words_used = 0;
fnt->kf_info = KF_FILE;
}
return(fnt);
}
/* Read the font information from the pxl file
* and remember that it is done
*/
getfontfromfile(fnt)
struct kyofont *fnt;
{
char fname[MAXNAMLEN];
FILE *f;
int i;
readpxlfile(fnt,fnt->kf_filename);
fnt->kf_info &= ~KF_FILE;
}
/* Calculate the number of words needed by symbol "c"
* for its pxl raster
*/
int char_words_needed(c)
struct kyochar *c;
{
return(((c->kc_width + 15) / 16) * c->kc_height);
}
/* Define a font.
* Can be called more than once for the same font.
*/
f_define_font(num,options,area,name,texmag,s,tfmchecksum)
char *area,*name;
unsigned long num,options,texmag,s,tfmchecksum;
{
int i;
/* check to see if font is already defined */
for(i = 0; i < ndvifonts ; i++) if (dvifonts[i].df_num == num) return;
/* Does this make too many fonts defined? */
if (ndvifonts >= MAXDVIFONTS) croak("too many dvi fonts");
dvifonts[ndvifonts].df_num = num;
dvifonts[ndvifonts++].df_kyofont = find_kyofont(area,name,texmag
,s,tfmchecksum);
}
/* Try to find DVI font with number "fontnum"
* in the dvi-fonttable
* Timestamp it to enable LRU font removal
*/
struct kyofont *
find_dvi_font(fontnum)
unsigned long fontnum;
{
register int i;
/* scan through the dvi font list. */
for(i = 0; i < ndvifonts ; i++)
if (dvifonts[i].df_num == fontnum) {
dvifonts[i].df_kyofont->kf_timestamp = timestamp++;
return(dvifonts[i].df_kyofont);
}
croak("no dvi font %d defined",fontnum);
}
/* Select a font as the current font */
f_use_font(fontnum,font_space)
unsigned long fontnum;
long *font_space;
{
curfnt = find_dvi_font(fontnum);
/* The font should be loaded already
* because loading fonts while printing a page
* could cause the Kyocera to emit the sheet
* that is printed on at this moment
*/
if (!(curfnt->kf_info & KF_LOADED))
croak("cannot load font %d while printing page", fontnum);
/* Start using it */
fprintf(kyo,"!R! FONT %1d;EXIT;",curfnt->kf_kyonumber);
*font_space = curfnt->kf_s / 6;
}
/* Put symbol "ch" to the printer
* "xsize" is the horizontal width of the character in pixels
*/
f_setc(ch, xsize)
unsigned long ch;
int xsize;
{
register struct kyochar *c = &(curfnt->kf_char[ch]);
/* When the symbol is to high it must be sent in raster format
* and canoot be loaded into the Kyocera
* Symbols higher than MAXKYOHEIGHT pixels cannot be loaded
*/
if (c->kc_info & KC_RASTER)
dev_raster(c);
else
dev_setc(ch, xsize);
}
/* Hints as to what fonts are to be used.
* This is called once per page to give fonts module instrucions as what fonts
* and characters in those fonts have to be loaded for this page.
* "fontvec" contains a list of fonts used for this page
* "veclen" is the number of fonts used on this page
* "charvec" contains the per font information about the symbols needed
*/
f_newpage(fontvec,charvec,veclen)
unsigned long fontvec[];
unsigned long charvec[][4];
int veclen;
{
struct kyochar *c;
register int i,j;
struct kyofont *f;
for (i = 0; i < veclen; i++) {
/* Lookup font in the dvi-fonttable
* and read the pxlfile if needed
*/
f = find_dvi_font(fontvec[i]);
if (f->kf_info & KF_FILE) getfontfromfile(f);
/* If not not loaded initialize space requirements */
if (!(f->kf_info & KF_LOADED)) {
f->kf_words_used = 0;
f->kf_words_needed = KF_MIN;
}
/* Determine which symbols should be loaded from this font */
for (j = 0; j < MAXCHARS; j++)
if (charvec[i][j/32] & (1 << (j % 32))) {
c = &(f->kf_char[j]);
c->kc_info |= KC_NEEDED;
if (!(c->kc_info & KC_LOADED))
f->kf_words_needed += char_words_needed(c);
} else f->kf_char[j].kc_info &= ~KC_NEEDED;
/* Load the symbols needed and not yet loaded */
download_font(f);
}
}
/* Load a font into the Kyocera */
download_font(fnt)
struct kyofont *fnt;
{
register int i;
/* Make free space if needed */
if (fnt->kf_words_needed > freewords)
kyofree(fnt->kf_words_needed);
freewords -= fnt->kf_words_needed;
fnt->kf_words_used += fnt->kf_words_needed;
/* Load needed symbols that are not yet loaded */
for (i = 0; i < MAXCHARS; i++)
if ((fnt->kf_char[i].kc_info & KC_NEEDED)
&& !(fnt->kf_char[i].kc_info & KC_LOADED))
load_char(i,fnt);
/* If font is loaded for the first time set its font attributes */
if (!(fnt->kf_info & KF_LOADED))
fprintf(kyo, "!R! FONT %1d; SFA 0,0,P,0;EXIT;",fnt->kf_kyonumber);
debug("Loaded %d words for font %s, %d\n",
fnt->kf_words_needed, fnt->kf_name, fnt->kf_kyonumber);
fnt->kf_words_needed = 0;
fnt->kf_info |= KF_LOADED;
}
/* Load symbol "ch" from font "fnt" */
load_char(ch,fnt)
unsigned long ch;
struct kyofont *fnt;
{
register unsigned short *bp;
register int w;
struct kyochar *c = &(fnt->kf_char[ch]);
int row,bw;
/* If symbol is too high it cannot be loaded
* and should be send as a raster each time it is used
*/
if (c->kc_height > MAXKYOHEIGHT) {
c->kc_info |= KC_RASTER;
return;
}
/* Does this symbol exist */
if (!(c->kc_glyph.l))
croak("Char %#x not in font %s\n",ch, fnt->kf_name);
/* Load metrics information about the symbol */
fprintf(kyo, "!R! LDFC %1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,0;"
,fnt->kf_kyonumber, visual(ch), c->kc_height, c->kc_width
,32*c->kc_yoffset,32*c->kc_xoffset
,32*c->kc_kyowidth, 16*c->kc_kyowidth);
/* Load the pixel raster */
bp = c->kc_glyph.p;
bw = (c->kc_width + 15) / 16;
for (row = 0; row < c->kc_height; row++) {
for (w = 0; w < bw; w++) convert(*bp++);
}
fprintf(kyo, "; EXIT;"); fflush(kyo);
c->kc_info |= KC_LOADED;
}
/* Convert pixel information into the format needed by the Kyocera */
convert(w)
unsigned short w;
{
char c;
c = ((w >> 10) & 077) + 64;
if (c == 127) c = '/'; putc(c, kyo);
c = ((w >> 4) & 077) + 64;
if (c == 127) c = '/'; putc(c, kyo);
c = (w & 017) + 48; putc(c, kyo);
}
/* Read the information for font "fnt" from file "fname" */
int readpxlfile(fnt,fname)
struct kyofont *fnt;
char *fname;
{
long pxl_id,pxl_dir_ptr;
long pxlchecksum;
FILE *f;
if (!(f = fopen(fname,"r"))) croak("no pxl file %s",fname);
if ((pxl_id = sget4(f)) != 1001)
croak("%d bad initial pxl ID; %s doesn't look like a pxl file",
pxl_id, fnt->kf_filename);
debug("OK This is a PXL file\n");
/* Read the last 5 longs from the pxl file */
(void) fseek(f, (long)(-5*4), 2);
pxlchecksum = sget4(f);
fnt->kf_pxl_mag_val = sget4(f);
fnt->kf_pxl_design_size = sget4(f);
pxl_dir_ptr = sget4(f);
if ((pxl_id = sget4(f)) != 1001)
croak("%d bad final pxl ID; %s doesn't look like a pxl file",
pxl_id, fnt->kf_filename);
if (pxl_dir_ptr != ftell(f) / 4 - 517)
croak("%s pxl dir ptr is %x, should be %x",
fnt->kf_filename, pxl_dir_ptr, ftell(f) / 4 - 517);
debug("pxl: checksum %d mag %d designsize %d dir %x\n",
pxlchecksum,fnt->kf_pxl_mag_val,
fnt->kf_pxl_design_size,pxl_dir_ptr);
if (fnt->kf_tfm_checksum & (pxlchecksum != fnt->kf_tfm_checksum)) {
fprintf(stderr, "Checksum mismatch: %s\n",fnt->kf_filename);
fprintf(stderr, " pxl file: %ld, tfm_file: %ld\n",
pxlchecksum, fnt->kf_tfm_checksum);
}
/* Read the directory */
(void) fseek(f, pxl_dir_ptr * 4, 0);
getpxldir(fnt,f);
debug(" %s max_height=%d\n",fnt->kf_filename,fnt->kf_maxheight);
/* Read in all the glyphs */
getglyphs(fnt,f);
(void) fclose(f);
}
/* Read the pixel directory for font "fnt" from file "f" */
getpxldir(fnt,f)
struct kyofont *fnt;
FILE *f;
{
int i;
struct kyochar *c;
double ds = ((double) fnt->kf_s) / ((double) (1 << 20));
/* Each symbol has an entry of 16 bytes */
fnt->kf_maxheight = 0;
for (i = 0; i < MAXCHARS; i++) {
c = &(fnt->kf_char[i]);
c->kc_width = sget2(f);
c->kc_height = sget2(f);
c->kc_xoffset = sget2(f);
c->kc_yoffset = sget2(f);
c->kc_glyph.l = get4(f);
c->kc_pxlwidth = sget4(f);
c->kc_texwidth = (long) (((double) c->kc_pxlwidth) * ds);
c->kc_kyowidth =
(c->kc_texwidth * numerator + half_denominator) / denominator;
/* Determine the maximum height of the font */
fnt->kf_maxheight = max(fnt->kf_maxheight,c->kc_height);
}
}
/* Read the raster information for font "fnt" from file "f"
* The information per symbol is a multiple of 4 bytes
* The information per symbol that will be loaded is a multiple of 2 bytes
*/
getglyphs(fnt,f)
struct kyofont *fnt;
FILE *f;
{
register int j,row;
register unsigned short *p;
int i,fbw,bw;
struct kyochar *c;
for (i = 0; i < MAXCHARS; i++) {
c = &(fnt->kf_char[i]);
if (c->kc_glyph.l) {
(void) fseek(f, c->kc_glyph.l * 4, 0);
fbw = ((c->kc_width + 31) / 32) * 2;
bw = (c->kc_width + 15) / 16;
if (!(p = (unsigned short *)malloc(2*bw * c->kc_height)))
croak("malloc %d",2*bw * c->kc_height);
c->kc_glyph.p = p;
for (row = 0; row < c->kc_height; row++) {
for (j = 0; j < bw; j++) *p++ = get2(f);
/* get rid of empty trailing bytes */
for (j = bw; j < fbw; j++) (void) get2(f);
}
}
}
}
/* This procedure is called for every character so it must be fast
* It returns the TeX width and the device width of symbol "ch"
*/
f_use_char(ch,texwidth,devwidth)
unsigned long ch;
long *texwidth,*devwidth;
{
register struct kyochar *c = &(curfnt->kf_char[ch]);
*texwidth = c->kc_texwidth;
*devwidth = c->kc_kyowidth;
}
/* free words by deleting font(s) using LRU strategy
* at least "words" words should be free
*/
int kyofree(words)
int words;
{
int i,oldtime;
struct kyofont *oldfont;
struct preload *oldpr;
while (words > freewords) {
oldpr = NULL;
/* First try preloaded fonts not yet used by this job */
for (i=0; i<nloaded; i++)
if (loaded[i].pr_info & PR_LOADED) {
oldpr = &loaded[i];
break;
}
/* Found one, delete it */
if (oldpr) {
oldpr->pr_info &= ~PR_LOADED;
fprintf(kyo,"!R! DELF %1d;EXIT;",oldpr->pr_font->pr_kyonumber);
fflush(kyo);
debug("Left free %ld\n", freewords);
debug("PRELOADED FONT %s, %d deleted, size %ld\n",
oldpr->pr_font->pr_name,
oldpr->pr_font->pr_kyonumber,
oldpr->pr_font->pr_words_used );
freewords += oldpr->pr_font->pr_words_used;
} else {
/* Try the other fonts now */
oldfont = NULL;
oldtime = timestamp;
for (i = 0; i < nkyofonts; i++)
if ((kyofonts[i]->kf_info & KF_LOADED)
&& (kyofonts[i]->kf_timestamp < oldtime)) {
oldfont = kyofonts[i];
oldtime = oldfont->kf_timestamp;
}
if (!oldfont) croak("kyofree bug");
oldfont->kf_info &= ~KF_LOADED;
oldfont->kf_words_needed = KF_MIN;
oldfont->kf_words_used = 0;
fprintf(kyo,"!R! DELF %1d;EXIT;",oldfont->kf_kyonumber);
fflush(kyo);
debug("Left free %ld\n", freewords);
debug("FONT %s, %d deleted, size %ld\n",
oldfont->kf_name,
oldfont->kf_kyonumber,
oldfont->kf_words_used);
freewords += oldfont->kf_words_used;
for (i = 0; i < MAXCHARS; i++) {
oldfont->kf_char[i].kc_info &= ~KC_LOADED;
if (oldfont->kf_char[i].kc_info & KC_NEEDED)
oldfont->kf_words_needed+=char_words_needed(&(oldfont->kf_char[i]));
}
}
}
}